#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <sys/select.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>

// 定义全局变量
struct gbm_device *gbm_dev;
struct gbm_surface *gbm_surf;
EGLDisplay egl_disp;
EGLContext egl_ctx;
EGLSurface egl_surf;
int drm_fd;
drmModeRes *resources;
drmModeConnector *connector;
drmModeEncoder *encoder;
drmModeCrtc *original_crtc;
uint32_t crtc_id;
drmModeModeInfo mode;

// 帧缓冲区相关
struct gbm_bo *current_bo = NULL;
struct gbm_bo *next_bo = NULL;
uint32_t fb_id = 0;

// 着色器程序相关
GLuint shader_program;
GLint position_location;
GLint color_location;

// 编译着色器
GLuint compile_shader(GLenum type, const char *source) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &source, NULL);
    glCompileShader(shader);
    
    GLint success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    if (!success) {
        char info_log[512];
        glGetShaderInfoLog(shader, 512, NULL, info_log);
        fprintf(stderr, "着色器编译失败: %s\n", info_log);
        return 0;
    }
    
    return shader;
}

// 创建着色器程序
void create_shader_program() {
    // 顶点着色器源码
    const char *vertex_shader_source = 
        "#version 100\n"
        "attribute vec3 position;\n"
        "attribute vec3 color;\n"
        "varying vec3 v_color;\n"
        "void main() {\n"
        "    gl_Position = vec4(position, 1.0);\n"
        "    v_color = color;\n"
        "}\n";
    
    // 片段着色器源码
    const char *fragment_shader_source = 
        "#version 100\n"
        "precision mediump float;\n"
        "varying vec3 v_color;\n"
        "void main() {\n"
        "    gl_FragColor = vec4(v_color, 1.0);\n"
        "}\n";
    
    GLuint vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_source);
    GLuint fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_source);
    
    if (!vertex_shader || !fragment_shader) {
        exit(1);
    }
    
    // 创建着色器程序
    shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, fragment_shader);
    glLinkProgram(shader_program);
    
    GLint success;
    glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
    if (!success) {
        char info_log[512];
        glGetProgramInfoLog(shader_program, 512, NULL, info_log);
        fprintf(stderr, "着色器程序链接失败: %s\n", info_log);
        exit(1);
    }
    
    // 获取属性位置
    position_location = glGetAttribLocation(shader_program, "position");
    color_location = glGetAttribLocation(shader_program, "color");
    
    // 清理着色器对象
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);
    
    printf("着色器程序创建成功\n");
}

// 查找可用的DRM设备
const char* find_drm_device() {
    static char device_path[64];
    
    printf("正在查找可用的DRM设备...\n");
    
    for (int i = 0; i < 8; i++) {
        snprintf(device_path, sizeof(device_path), "/dev/dri/card%d", i);
        printf("尝试 %s...", device_path);
        
        int test_fd = open(device_path, O_RDWR | O_CLOEXEC);
        if (test_fd >= 0) {
            printf(" ✅ 可用\n");
            close(test_fd);
            return device_path;
        } else {
            printf(" ❌ 失败: %s\n", strerror(errno));
        }
    }
    
    printf("❌ 未找到可用的DRM设备\n");
    return NULL;
}

// 初始化 DRM/KMS 和 GBM
int init_drm(const char *dri_device) {
    printf("正在初始化 DRM 设备: %s\n", dri_device);
    
    drm_fd = open(dri_device, O_RDWR | O_CLOEXEC);
    if (drm_fd < 0) {
        perror("Failed to open DRM device");
        return -1;
    }

    // 获取 DRM 资源
    resources = drmModeGetResources(drm_fd);
    if (!resources) {
        perror("Failed to get DRM resources");
        close(drm_fd);
        return -1;
    }

    // 查找连接器
    for (int i = 0; i < resources->count_connectors; i++) {
        connector = drmModeGetConnector(drm_fd, resources->connectors[i]);
        if (connector->connection == DRM_MODE_CONNECTED) {
            printf("找到连接的显示器: %dx%d\n", 
                   connector->modes[0].hdisplay, 
                   connector->modes[0].vdisplay);
            break;
        }
        drmModeFreeConnector(connector);
        connector = NULL;
    }

    if (!connector) {
        fprintf(stderr, "没有找到连接的显示器\n");
        drmModeFreeResources(resources);
        close(drm_fd);
        return -1;
    }

    // 获取显示模式信息
    mode = connector->modes[0];
    printf("使用显示模式: %dx%d@%dHz\n", 
           mode.hdisplay, mode.vdisplay, mode.vrefresh);

    // 查找编码器和 CRTC
    for (int i = 0; i < resources->count_encoders; i++) {
        encoder = drmModeGetEncoder(drm_fd, resources->encoders[i]);
        if (encoder && encoder->encoder_id == connector->encoder_id) {
            crtc_id = encoder->crtc_id;
            break;
        }
        if (encoder) {
            drmModeFreeEncoder(encoder);
            encoder = NULL;
        }
    }

    if (!encoder || !crtc_id) {
        // 如果没有找到当前编码器，尝试找一个可用的 CRTC
        for (int i = 0; i < resources->count_crtcs; i++) {
            crtc_id = resources->crtcs[i];
            break;
        }
        if (!crtc_id) {
            fprintf(stderr, "没有找到可用的 CRTC\n");
            drmModeFreeConnector(connector);
            drmModeFreeResources(resources);
            close(drm_fd);
            return -1;
        }
    }

    // 保存原始 CRTC 设置，以便恢复
    original_crtc = drmModeGetCrtc(drm_fd, crtc_id);
    printf("找到 CRTC ID: %u\n", crtc_id);

    // 初始化 GBM
    printf("正在初始化 GBM 设备\n");
    gbm_dev = gbm_create_device(drm_fd);
    if (!gbm_dev) {
        perror("Failed to create GBM device");
        drmModeFreeConnector(connector);
        drmModeFreeResources(resources);
        close(drm_fd);
        return -1;
    }

    printf("DRM/GBM 初始化成功\n");
    return drm_fd;
}

// 初始化 EGL 和 OpenGL ES
void init_egl() {
    printf("正在初始化 EGL\n");
    
    // 获取 EGL Display
    egl_disp = eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, gbm_dev, NULL);
    if (egl_disp == EGL_NO_DISPLAY) {
        fprintf(stderr, "Failed to get EGL display\n");
        exit(1);
    }

    // 初始化 EGL
    if (!eglInitialize(egl_disp, NULL, NULL)) {
        fprintf(stderr, "EGL initialization failed\n");
        exit(1);
    }

    printf("EGL 版本: %s\n", eglQueryString(egl_disp, EGL_VERSION));
    printf("EGL 供应商: %s\n", eglQueryString(egl_disp, EGL_VENDOR));

    // 配置 EGL
    EGLint config_attrs[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_DEPTH_SIZE, 24,
        EGL_NONE
    };
    EGLConfig cfg;
    EGLint num_configs;
    if (!eglChooseConfig(egl_disp, config_attrs, &cfg, 1, &num_configs) || num_configs == 0) {
        fprintf(stderr, "Failed to choose EGL config\n");
        exit(1);
    }
    
    printf("选择了 EGL 配置\n");

    // 创建 EGL Surface
    int width = mode.hdisplay;
    int height = mode.vdisplay;
    printf("创建 GBM surface: %dx%d\n", width, height);
    
    gbm_surf = gbm_surface_create(gbm_dev, width, height, GBM_FORMAT_XRGB8888,
                                  GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
    if (!gbm_surf) {
        fprintf(stderr, "Failed to create GBM surface\n");
        exit(1);
    }
    
    egl_surf = eglCreatePlatformWindowSurface(egl_disp, cfg, gbm_surf, NULL);
    if (egl_surf == EGL_NO_SURFACE) {
        fprintf(stderr, "Failed to create EGL surface\n");
        exit(1);
    }

    // 创建 EGL Context
    EGLint ctx_attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    egl_ctx = eglCreateContext(egl_disp, cfg, EGL_NO_CONTEXT, ctx_attrs);
    if (egl_ctx == EGL_NO_CONTEXT) {
        fprintf(stderr, "Failed to create EGL context\n");
        exit(1);
    }
    
    if (!eglMakeCurrent(egl_disp, egl_surf, egl_surf, egl_ctx)) {
        fprintf(stderr, "Failed to make EGL context current\n");
        exit(1);
    }
    
    printf("OpenGL ES 版本: %s\n", glGetString(GL_VERSION));
    printf("OpenGL ES 渲染器: %s\n", glGetString(GL_RENDERER));
    
    // 创建着色器程序
    create_shader_program();
    
    printf("EGL 初始化完成\n");
}

// 创建 DRM 帧缓冲区
uint32_t create_fb_for_bo(struct gbm_bo *bo) {
    uint32_t fb_id;
    uint32_t width = gbm_bo_get_width(bo);
    uint32_t height = gbm_bo_get_height(bo);
    uint32_t stride = gbm_bo_get_stride(bo);
    uint32_t handle = gbm_bo_get_handle(bo).u32;
    
    int ret = drmModeAddFB(drm_fd, width, height, 24, 32, stride, handle, &fb_id);
    if (ret) {
        fprintf(stderr, "Failed to create framebuffer: %d\n", ret);
        return 0;
    }
    
    return fb_id;
}

// 页面翻转完成的回调函数
static void page_flip_handler(int fd __attribute__((unused)), 
                             unsigned int frame __attribute__((unused)), 
                             unsigned int sec __attribute__((unused)), 
                             unsigned int usec __attribute__((unused)), 
                             void *data) {
    int *flip_pending = (int *)data;
    *flip_pending = 0;
}

// 渲染三角形并显示到屏幕
void render() {
    static int frame = 0;
    static int flip_pending = 0;
    static int first_frame = 1;
    frame++;
    
    // 使用不同颜色来显示动画效果
    float r = 0.2f + 0.3f * (float)sin(frame * 0.05f);
    float g = 0.3f + 0.3f * (float)cos(frame * 0.05f);
    float b = 0.3f;
    
    glClearColor(r, g, b, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // 使用着色器程序
    glUseProgram(shader_program);

    // 渲染彩色三角形
    const GLfloat vertices[] = {
         0.0f,  0.6f, 0.0f,  // 顶点
        -0.6f, -0.6f, 0.0f,  // 左下
         0.6f, -0.6f, 0.0f   // 右下
    };
    
    const GLfloat colors[] = {
        1.0f, 0.0f, 0.0f,    // 红色
        0.0f, 1.0f, 0.0f,    // 绿色
        0.0f, 0.0f, 1.0f     // 蓝色
    };

    // 设置顶点位置属性
    glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    glEnableVertexAttribArray(position_location);
    
    // 设置顶点颜色属性
    glVertexAttribPointer(color_location, 3, GL_FLOAT, GL_FALSE, 0, colors);
    glEnableVertexAttribArray(color_location);
    
    // 绘制三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);
    
    // 禁用顶点属性
    glDisableVertexAttribArray(position_location);
    glDisableVertexAttribArray(color_location);
    
    if (!eglSwapBuffers(egl_disp, egl_surf)) {
        fprintf(stderr, "Failed to swap buffers\n");
        return;
    }
    
    // 获取渲染后的缓冲区
    next_bo = gbm_surface_lock_front_buffer(gbm_surf);
    if (!next_bo) {
        fprintf(stderr, "Failed to lock front buffer\n");
        return;
    }
    
    uint32_t next_fb_id = create_fb_for_bo(next_bo);
    if (!next_fb_id) {
        gbm_surface_release_buffer(gbm_surf, next_bo);
        return;
    }
    
    // 等待之前的页面翻转完成
    if (flip_pending) {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(drm_fd, &fds);
        
        drmEventContext evctx = {
            .version = DRM_EVENT_CONTEXT_VERSION,
            .page_flip_handler = page_flip_handler,
        };
        
        while (flip_pending) {
            int ret = select(drm_fd + 1, &fds, NULL, NULL, NULL);
            if (ret < 0) {
                perror("select failed");
                break;
            }
            drmHandleEvent(drm_fd, &evctx);
        }
    }
    
    // 第一帧需要设置 CRTC
    if (first_frame) {
        int ret = drmModeSetCrtc(drm_fd, crtc_id, next_fb_id, 0, 0,
                                &connector->connector_id, 1, &mode);
        if (ret) {
            fprintf(stderr, "Failed to set CRTC: %d\n", ret);
        } else {
            printf("成功设置显示模式并显示到屏幕\n");
        }
        first_frame = 0;
    } else {
        // 后续帧使用页面翻转
        int ret = drmModePageFlip(drm_fd, crtc_id, next_fb_id,
                                 DRM_MODE_PAGE_FLIP_EVENT, &flip_pending);
        if (ret) {
            fprintf(stderr, "Failed to page flip: %d\n", ret);
        } else {
            flip_pending = 1;
        }
    }
    
    // 清理之前的缓冲区
    if (current_bo) {
        if (fb_id) {
            drmModeRmFB(drm_fd, fb_id);
        }
        gbm_surface_release_buffer(gbm_surf, current_bo);
    }
    
    current_bo = next_bo;
    fb_id = next_fb_id;
    
    if (frame % 60 == 0) {  // 每秒输出一次
        printf("渲染帧 %d - 彩色三角形显示到屏幕\n", frame);
    }
}

int main() {
    printf("开始 DRM EGL 测试程序 - 将显示彩色三角形到屏幕\n");
    
    // 1. 查找并初始化第一个可用的DRM设备
    const char* drm_device = find_drm_device();
    if (!drm_device) {
        fprintf(stderr, "没有找到可用的DRM设备\n");
        return -1;
    }
    
    printf("使用DRM设备: %s\n", drm_device);
    
    if (init_drm(drm_device) < 0) {
        fprintf(stderr, "DRM 初始化失败\n");
        return -1;
    }

    // 2. 初始化 EGL 和 OpenGL ES
    init_egl();

    printf("开始渲染循环，将渲染 1800 帧 (30秒)...\n");
    printf("您应该能在屏幕上看到一个彩色三角形：顶部红色，左下绿色，右下蓝色\n");
    printf("背景颜色也会慢慢变化\n");
    
    // 3. 渲染循环 - 30秒显示
    for (int i = 0; i < 1800; ++i) { // 渲染 1800 帧 (30秒)
        render();
        usleep(16667); // ~60 FPS (16.67ms)
    }

    printf("渲染完成，恢复屏幕并清理资源\n");

    // 清理着色器程序
    glDeleteProgram(shader_program);

    // 恢复原始 CRTC 设置
    if (original_crtc) {
        drmModeSetCrtc(drm_fd, original_crtc->crtc_id, original_crtc->buffer_id,
                      original_crtc->x, original_crtc->y,
                      &connector->connector_id, 1, &original_crtc->mode);
        drmModeFreeCrtc(original_crtc);
    }

    // 4. 清理资源
    if (current_bo) {
        if (fb_id) {
            drmModeRmFB(drm_fd, fb_id);
        }
        gbm_surface_release_buffer(gbm_surf, current_bo);
    }
    
    eglDestroyContext(egl_disp, egl_ctx);
    eglDestroySurface(egl_disp, egl_surf);
    eglTerminate(egl_disp);
    gbm_surface_destroy(gbm_surf);
    gbm_device_destroy(gbm_dev);
    
    if (encoder) drmModeFreeEncoder(encoder);
    if (connector) drmModeFreeConnector(connector);
    if (resources) drmModeFreeResources(resources);
    close(drm_fd);

    printf("屏幕已恢复，程序结束\n");
    return 0;
}

